#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <unistd.h>
#include <iostream>
#include <atomic>

#include "drm_drv/drm_plane_drv.h"
#include "v4l2_drv/v4l2_capture.h"
#include "fb_drv/fb_drv.h"
#include "pipe_stream.h"
#include "pipe_merge.h"
#include "display_mode.h"


#include "opencv2/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

using namespace cv;
using namespace std;

struct drm_plane plane[10];
struct drm_plane dp_plane[10];
Capture cap[10];
Pipe_Stream pipe_s[10];
Pipe_Merge pipe_merge;
Pipe_Merge pipe_merge2;

struct drm_card dp_card;
struct drm_card hdmi_card;

struct fb_card fb0_card;

void hdmi_in_hdmi_out_test(void){
    int fd;
    setbuf(stdout,NULL);
    Mat rgb,yuv;

    drm_card_init(&hdmi_card,"/dev/dri/card0");
    drm_card_init(&dp_card,"/dev/dri/card1");

    drm_card_print_info(hdmi_card);
    drm_card_print_info(dp_card);

    Capture hdmi_in0=Capture(1920,1080,V4L2_PIX_FMT_RGB24);
    hdmi_in0.initCapture(9);

    for(int i=0;i<8;i++){
        cap[i].initCapture(i);
    }
    sleep(1);

//cap_in dp_out test
    init_plane(&dp_plane[0],dp_card,39,1920,1080,0,0,DRM_FORMAT_BGR888);
    pipe_s[0].start(&cap[0],&dp_plane[0],nv12_rgb);
//hdmi_in  dp_out test
    init_plane(&plane[0],hdmi_card,33,1280,720,0,0,DRM_FORMAT_RGB888);
    pipe_s[1].start(&hdmi_in0,&plane[0],rgb_rgb);

    while(1);
}

void cap1_in_hdmi_out_test(void){

    int fd;
    setbuf(stdout,NULL);
    Mat rgb,yuv;

    drm_card_init(&hdmi_card,"/dev/dri/card0");
    drm_card_print_info(hdmi_card);

    for(int i=0;i<8;i++){
        cap[i].initCapture(i);
    }
    sleep(1);

    init_plane(&plane[0],hdmi_card,33,1280,720,0,0,DRM_FORMAT_RGB888);
    pipe_s[0].start(&cap[0],&plane[0],nv12_rgb);

    while(true);
}


void cap6_in_hdmi_out_test(void){

    int fd;
    setbuf(stdout,NULL);
    Mat rgb,yuv;

    drm_card_init(&hdmi_card,"/dev/dri/card0");
    drm_card_print_info(hdmi_card);

    for(int i=0;i<8;i++){
        cap[i].initCapture(i);
    }
    sleep(1);

    init_plane(&plane[0],hdmi_card,33,640,360,0,0,DRM_FORMAT_RGB888);
    pipe_s[0].start(&cap[0],&plane[0],nv12_rgb);
    init_plane(&plane[1],hdmi_card,34,640,360,640,0,DRM_FORMAT_RGB888);
    pipe_s[1].start(&cap[1],&plane[1],nv12_rgb);

    init_plane(&plane[2],hdmi_card,35,640,360,1280,0,DRM_FORMAT_RGB888);
    pipe_s[2].start(&cap[2],&plane[2],nv12_rgb);

    init_plane(&plane[3],hdmi_card,36,640,360,0,360,DRM_FORMAT_RGB888);
    pipe_s[3].start(&cap[3],&plane[3],nv12_rgb);

    init_plane(&plane[4],hdmi_card,37,640,360,640,360,DRM_FORMAT_RGB888);
    pipe_s[4].start(&cap[4],&plane[4],nv12_rgb);

    init_plane(&plane[5],hdmi_card,38,640,360,1280,360,DRM_FORMAT_NV12);
    pipe_s[5].start(&cap[5],&plane[5],nv12_nv12);

    while(true);
}


void video_switch_hdmi_out_test(void){

    int fd;
    setbuf(stdout,NULL);
    Mat rgb,yuv;

    drm_card_init(&hdmi_card,"/dev/dri/card0");
    drm_card_print_info(hdmi_card);

    for(int i=0;i<8;i++){
        cap[i].initCapture(i);
    }
    sleep(1);

    while (true) {
        pipe_stop_all(pipe_s);
        pipe_merge.stop();
        printf("screen-merge");
        screen_mode(hdmi_card,plane,10,screen14x25x36);
//        pipe_s[i].start(&cap[i],&plane[i],nv12_rgb);
        pipe_merge.start(&cap[0],&cap[1],&plane[0]);
        sleep(5);
        printf("Pipe_HONGWAI\n");
        pipe_merge.setMergemode(Pipe_HONGWAI);
        sleep(5);
        printf("Pipe_WEIGUANG\n");
        pipe_merge.setMergemode(Pipe_WEIGUANG);
        sleep(5);
        printf("red color\n");
        pipe_merge.setMergemode(Pipe_MERGE);
        pipe_merge.setColormode(true);
        sleep(5);

        pipe_merge.stop();
        pipe_stop_all(pipe_s);
        printf("screen123456");
        screen_mode(hdmi_card,plane,10,screen123456);
        for(int i=0;i<1;i++){
            pipe_s[i].start(&cap[i],&plane[i],nv12_rgb);
        }
        sleep(5);

        pipe_stop_all(pipe_s);
        printf("screen14x25x36");
        screen_mode(hdmi_card,plane,10,screen14x25x36);
        for(int i=0;i<3;i++)
            pipe_s[i].start(&cap[i],&plane[i],nv12_rgb);
        sleep(5);

        printf("screen1x2x3x4x5x6");
        pipe_stop_all(pipe_s);
        screen_mode(hdmi_card,plane,10,screen123x4x5x6);
        for(int i=0;i<4;i++)
            pipe_s[i].start(&cap[i],&plane[i],nv12_rgb);
        sleep(5);

        printf("screen1x2x3x4x5x6");
        pipe_stop_all(pipe_s);
        screen_mode(hdmi_card,plane,10,screen1x2x3x456);
        for(int i=0;i<4;i++)
            pipe_s[i].start(&cap[i],&plane[i],nv12_rgb);
        sleep(5);

        printf("screen1x2x3x4x5x6");
        pipe_stop_all(pipe_s);
        screen_mode(hdmi_card,plane,10,screen1x2x3x4x5x6);
        for(int i=0;i<6;i++)
            pipe_s[i].start(&cap[i],&plane[i],nv12_rgb);
    }

    sleep(5);
//    pipe_s[1].stop();
//    pipe_s[2].stop();
//    pipe_s[3].stop();
////    pipe_s[4].stop();
//    pipe_s[1].wait_stoping();
//    pipe_s[2].wait_stoping();
//    pipe_s[3].wait_stoping();
////    pipe_s[4].wait_stoping();
//    sleep(5);
//    pipe_s[1].start(&cap[1],&plane[1],nv12_nv12);

//    plane_destroy(&plane[1]);
    while(1){
        sleep(1);
    }

    while(true);
}


void merge1_hdmi_out_test(void){

    int fd;
    setbuf(stdout,NULL);
    Mat rgb,yuv;

    drm_card_init(&hdmi_card,"/dev/dri/card0");
    drm_card_print_info(hdmi_card);

    for(int i=0;i<8;i++){
        cap[i].initCapture(i);
    }
    sleep(1);

    while (true) {
        pipe_stop_all(pipe_s);
        pipe_merge.stop();
        printf("screen-merge");
        screen_mode(hdmi_card,plane,10,screen14x25x36_fzjs);
//        pipe_s[i].start(&cap[i],&plane[i],nv12_rgb);
        pipe_merge.setColormode(true);
//        pipe_merge.setMergemode(Pipe_HONGWAI);
        pipe_merge.start(&cap[0],&cap[1],&plane[1]);

        sleep(5);
        while(1){
            sleep(1);
        }
        printf("Pipe_HONGWAI\n");
        pipe_merge.setMergemode(Pipe_HONGWAI);
        while(1){
            sleep(1);
        }
        sleep(5);
        printf("Pipe_WEIGUANG\n");
        pipe_merge.setMergemode(Pipe_WEIGUANG);
        sleep(5);
        while(1){
            sleep(1);
        }
        printf("red color\n");
        pipe_merge.setMergemode(Pipe_MERGE);
        pipe_merge.setColormode(true);
        while(1){
            sleep(1);
        }
        sleep(5);
    }
    while(1){
        sleep(1);
    }
}

void merge2_hdmi_out_test(void){

    int fd;
    setbuf(stdout,NULL);
    Mat rgb,yuv;

    drm_card_init(&hdmi_card,"/dev/dri/card0");
    drm_card_print_info(hdmi_card);

    for(int i=0;i<8;i++){
        cap[i].initCapture(i);
    }
    sleep(1);

    while (true) {
        pipe_stop_all(pipe_s);
        pipe_merge.stop();
        printf("screen-merge");
        screen_mode(hdmi_card,plane,10,screen14x25x36_fzjs);
        pipe_s[0].start(&cap[5],&plane[0],nv12_rgb);
        pipe_s[1].start(&cap[6],&plane[2],nv12_rgb);

//        pipe_s[i].start(&cap[i],&plane[i],nv12_rgb);
//        pipe_merge.start(&cap[0],&cap[1],&plane[1]);
        pipe_merge.start_alone(&cap[0],&cap[1],&plane[1],false);
        pipe_merge2.start_alone(&cap[0],&cap[1],&plane[3],true);

        pipe_merge.setColormode(true);
        pipe_merge2.setColormode(true);
//        pipe_merge.setMergemode(Pipe_HONGWAI);

        sleep(5);
        while(1){
            sleep(1);
        }
        printf("Pipe_HONGWAI\n");
        pipe_merge.setMergemode(Pipe_HONGWAI);
        while(1){
            sleep(1);
        }
        sleep(5);
        printf("Pipe_WEIGUANG\n");
        pipe_merge.setMergemode(Pipe_WEIGUANG);
        sleep(5);
        while(1){
            sleep(1);
        }
        printf("red color\n");
        pipe_merge.setMergemode(Pipe_MERGE);
        pipe_merge.setColormode(true);
        while(1){
            sleep(1);
        }
        sleep(5);
    }
    while(1){
        sleep(1);
    }
}

#include<queue>
#include<condition_variable>

std::mutex mut;
std::queue<Mat> data_queue;	// 用于线程间通信的队列
std::condition_variable data_cond;

void data_preparation_thread_nv12()
{
    long int t1=0,t2=0;
    int fps_cnt=0;
    float time;

    sleep(3);
    while(1)
    {
//heng zhe
        Mat nv12(720*3/2, 1280*8, CV_8UC1);
//shu zhe
//        Mat nv12(720*3*6/2, 1280, CV_8UC1);
//        usleep(1000*100);
//        Mat bgr;
//        std::cout << "data queue size : " <<data_queue.size()<< std::endl;
        for(int i=0;i<6;++i)
        {
            Frame frame=cap[i].getLastFrame();
            if(frame.data==nullptr){
                fprintf(stderr,"v4l2 capture  erro frame.data is null ");
                sleep(1);
                continue;
            }
//            printf("stitch video:%d,buffer_index:%d add:%ld \r\n",i,index,p);
//heng zhe
            int base1=i*1280;
            for(int j=0;j<720*3/2;j++){
                memcpy(nv12.data+base1+(1280*8*j),frame.data+(1280*j), 1280);
            }

//shu zhe
//            int base1=i*720*1280;
//            int base2=i*360*1280;
//            memcpy(nv12.data+base1,p, 1280*720);
//            memcpy(nv12.data+(1280*720*6)+base2,p+(1280*720), 1280*360);
        }
        fps_cnt++;
        if(fps_cnt>25){
            t2 =cv::getTickCount();
            time=(t2-t1)/cv::getTickFrequency();
            std::cout <<"capture fps:::: s  "<<fps_cnt/time<<endl;
            t1 =cv::getTickCount();
            fps_cnt=0;
        }
//        cvtColor(nv12, bgr, CV_YUV2RGB_NV12);
//        cout<<bgr.size<<"channels"<<bgr.channels()<<endl;
//        std::lock_guard<std::mutex> lk(mut);
//        usleep(20*000);

        mut.lock();
        data_queue.push(nv12);
//        std::cout << "data_preparation_thread notify_one" << std::endl;
        data_cond.notify_one();
        mut.unlock();
    }
}
void display8_fb_card(void){

    int fd;
    setbuf(stdout,NULL);
    Mat rgb,yuv;

    drm_card_init(&hdmi_card,"/dev/dri/card1");
    drm_card_print_info(hdmi_card);

    fb_card_init(&fb0_card,"/dev/fb0");
    fb_card_print_info(fb0_card);


    init_plane(&plane[0],hdmi_card,33,1920,720,0,0,DRM_FORMAT_RGB888);

    for(int i=0;i<6;i++){
        cap[i].initCapture(i);
    }
    sleep(1);

    std::thread data_prepar(data_preparation_thread_nv12);
    pthread_setname_np(data_prepar.native_handle(),"record_pre_nv12");
    Mat output;
    int i=0;
     while(true)
     {
 //        std::cout << "data_processing_thread while" << std::endl;
         std::unique_lock<std::mutex> lk(mut);
 //        std::cout << "data_processing_thread before wait" << std::endl;
         data_cond.wait(lk,[]{return !data_queue.empty();});
 //        std::cout << "data_processing_thread pass wait" << std::endl;
         Mat nv12=data_queue.front();
         data_queue.pop();
         lk.unlock();
         Mat bgr;
         cvtColor(nv12, bgr, CV_YUV2RGB_NV12);
 //        cout<<"sizeof bgr"<<bgr.size<<endl;
         resize(bgr,output,Size(1920,720));

         i++;
//         string filename="/home/root/picture/"+to_string(i)+".jpg";
//         cout<<filename<<endl;
//         imwrite(filename,output);
//         fb_double_cpy(&fb0_card,output.data,output.rows*output.cols*output.elemSize());
         plane_double_fb_cpy(&plane[0],output.data,output.rows*output.cols*output.elemSize());
//         std::cout << "Mat data: " <<output.size()<< std::endl;

     }
}

int main(void){

//    hdmi_in_hdmi_out_test();

//    cap1_in_hdmi_out_test();

//    cap6_in_hdmi_out_test();

//    video_switch_hdmi_out_test();

//    merge2_hdmi_out_test();

    display8_fb_card();

//    test_all();

    return 0;

}


int test_all(void){

    int fd;
    setbuf(stdout,NULL);
    Mat rgb,yuv;

    drm_card_init(&hdmi_card,"/dev/dri/card0");
    drm_card_init(&dp_card,"/dev/dri/card1");

    drm_card_print_info(hdmi_card);
    drm_card_print_info(dp_card);

//    while(true);
//设置drm分层的透明度属性。
//    drm_alpha_init();

    Capture hdmi_in0=Capture(1920,1080,V4L2_PIX_FMT_RGB24);
    hdmi_in0.initCapture(9);
//    Capture hdmi_in1=Capture(1920,1080,V4L2_PIX_FMT_BGR24);
//    hdmi_in1.initCapture(10);

    for(int i=0;i<8;i++){
//        cap[i].initCapture(7-i);
        cap[i].initCapture(i);
    }

//    init_plane(&plane[5],37,720,720,360,0,DRM_FORMAT_RGB888);
//    Pipe_Merge merge;
//    merge.start(&cap[4],&cap[5],&plane[5]);

    while (true) {
        pipe_stop_all(pipe_s);
        pipe_merge.stop();
        printf("screen-merge");
        screen_mode(hdmi_card,plane,10,screen14x25x36);
//        pipe_s[i].start(&cap[i],&plane[i],nv12_rgb);
        pipe_merge.start(&cap[0],&cap[1],&plane[0]);
        sleep(5);
        printf("Pipe_HONGWAI\n");
        pipe_merge.setMergemode(Pipe_HONGWAI);
        sleep(5);
        printf("Pipe_WEIGUANG\n");
        pipe_merge.setMergemode(Pipe_WEIGUANG);
        sleep(5);
        printf("red color\n");
        pipe_merge.setMergemode(Pipe_MERGE);
        pipe_merge.setColormode(true);
        sleep(5);

        pipe_merge.stop();
        pipe_stop_all(pipe_s);
        printf("screen123456");
        screen_mode(hdmi_card,plane,10,screen123456);
        for(int i=0;i<1;i++){
            pipe_s[i].start(&cap[i],&plane[i],nv12_rgb);
        }
        sleep(5);

        pipe_stop_all(pipe_s);
        printf("screen14x25x36");
        screen_mode(hdmi_card,plane,10,screen14x25x36);
        for(int i=0;i<3;i++)
            pipe_s[i].start(&cap[i],&plane[i],nv12_rgb);
        sleep(5);

        printf("screen1x2x3x4x5x6");
        pipe_stop_all(pipe_s);
        screen_mode(hdmi_card,plane,10,screen123x4x5x6);
        for(int i=0;i<4;i++)
            pipe_s[i].start(&cap[i],&plane[i],nv12_rgb);
        sleep(5);

        printf("screen1x2x3x4x5x6");
        pipe_stop_all(pipe_s);
        screen_mode(hdmi_card,plane,10,screen1x2x3x456);
        for(int i=0;i<4;i++)
            pipe_s[i].start(&cap[i],&plane[i],nv12_rgb);
        sleep(5);

        printf("screen1x2x3x4x5x6");
        pipe_stop_all(pipe_s);
        screen_mode(hdmi_card,plane,10,screen1x2x3x4x5x6);
        for(int i=0;i<6;i++)
            pipe_s[i].start(&cap[i],&plane[i],nv12_rgb);
        sleep(5);
    }

//    screen_mode(hdmi_card,plane,10,screen3x1);


    sleep(5);
//    pipe_s[1].stop();
//    pipe_s[2].stop();
//    pipe_s[3].stop();
////    pipe_s[4].stop();
//    pipe_s[1].wait_stoping();
//    pipe_s[2].wait_stoping();
//    pipe_s[3].wait_stoping();
////    pipe_s[4].wait_stoping();
//    sleep(5);
//    pipe_s[1].start(&cap[1],&plane[1],nv12_nv12);

//    plane_destroy(&plane[1]);
    while(1){
        sleep(1);
    }
    sleep(4);
    plane_destroy(&plane[0]);
    close(fd);
    sleep(5);
}


